#include "featuretablemodel.h"


#include <characterfeature.h>


#include <QList>


FeatureTableModel::FeatureTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
}

void FeatureTableModel::setCampaign(Campaign *campaign)
{
    if (m_campaign.data() == campaign)
    {
        return;
    }

    beginResetModel();
    m_characterClasses = 0;
    m_campaign = campaign;

    if (!m_campaign.isNull())
    {
        m_characterClasses = m_campaign->findChild<CharacterClasses*>(QString(), Qt::FindDirectChildrenOnly);
    }
    endResetModel();
}

int FeatureTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)

    if (!ready())
    {
        return 0;
    }

    return m_characterClasses->findChildren<const CharacterClass*>(QString(), Qt::FindDirectChildrenOnly).count();
}

int FeatureTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if (!ready())
    {
        return 0;
    }

    // todo: character features should be available from campaign when custom features can be defined.
    return CharacterFeatures::WillSave - CharacterFeatures::HitDie + 2;
}

QVariant FeatureTableModel::data(const QModelIndex &index, int role) const
{
    if (!ready() || !index.isValid())
    {
        return QVariant();
    }

    if (role != Qt::EditRole && role != Qt::DisplayRole)
    {
        return QVariant();
    }

    QList<const CharacterClass*> classList = m_characterClasses->findChildren<const CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.row() >= classList.count())
    {
        return QVariant();
    }

    const CharacterClass* characterClass = classList.at(index.row());

    if (index.column() == 0)
    {
        return characterClass->name();
    }

    int featureIndex = index.column()-1;
    int featureValue = characterClass->featureValue(featureIndex);

    int offset = CharacterFeature::staticMetaObject.enumeratorOffset();

    switch (featureIndex)
    {
    case CharacterFeatures::HitDie:
        return CharacterFeature::staticMetaObject
                .enumerator(offset)
                .valueToKey(featureValue);

    case CharacterFeatures::SkillPoints:
        return QString("%1 (%2)")
                .arg(CharacterFeature::staticMetaObject
                     .enumerator(offset+1)
                     .valueToKey(featureValue))
                .arg(featureValue)
                .simplified();

    case CharacterFeatures::BaseAttack:
        return CharacterFeature::staticMetaObject
                .enumerator(offset+2)
                .valueToKey(featureValue);

    case CharacterFeatures::FortSave:
    case CharacterFeatures::RefSave:
    case CharacterFeatures::WillSave:
        return CharacterFeature::staticMetaObject
                .enumerator(offset+3)
                .valueToKey(featureValue);

    default:
        break;
    }

    return tr("[unknown]");

//    return characterClass->featureValue(index.column()-1);
}

QVariant FeatureTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::TextAlignmentRole && orientation == Qt::Horizontal)
    {
        return Qt::AlignCenter;
    }

    if (role != Qt::DisplayRole)
    {
        return QAbstractTableModel::headerData(section, orientation, role);
    }

    if (orientation == Qt::Vertical)
    {
        return QAbstractTableModel::headerData(section, orientation, role);
    }

    int featureIndex = section - 1;
    if (featureIndex < 0)
    {
        return tr("Character Class");
    }

    switch (featureIndex)
    {
    case CharacterFeatures::HitDie:
        return tr("Hit Die");
    case CharacterFeatures::SkillPoints:
        return tr("Skill Points");
    case CharacterFeatures::BaseAttack:
        return tr("Base Attack");
    case CharacterFeatures::FortSave:
        return tr("Fort Save");
    case CharacterFeatures::RefSave:
        return tr("Ref Save");
    case CharacterFeatures::WillSave:
        return tr("Will Save");
    default:
        break;
    }

    return tr("[Not Set]");
}

bool FeatureTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!ready() || !index.isValid() || role != Qt::EditRole)
    {
        return false;
    }

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.column() >= characterClassList.count())
    {
        return false;
    }

    CharacterClass* characterClass = characterClassList.at(index.row());
    if (index.column() == 0)
    {
        characterClass->setName(value.toString());
        emit dataChanged(index, index);
        return true;
    }

    int featureIndex = index.column()-1;

    if (!characterClass->setFeatureValue(featureIndex, value))
    {
        return false;
    }

    emit dataChanged(index, index);
    return true;

}

bool FeatureTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(count)

    if (parent.isValid() || !ready())
    {
        return false;
    }

    beginInsertRows(parent, row, row);
    m_characterClasses->newChild("New Character Class");
    endInsertRows();

    return true;
}

bool FeatureTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(count)

    if (!ready() || parent.isValid())
    {
        return false;
    }

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (row < 0 || row >= characterClassList.count())
    {
        return false;
    }

    beginRemoveRows(parent, row, row);
    CharacterClass* characterClass = characterClassList.at(row);
    characterClass->setParent(0);
    characterClass->deleteLater();
    endRemoveRows();
    return true;
}

Qt::ItemFlags FeatureTableModel::flags(const QModelIndex &index) const
{
    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}


bool FeatureTableModel::ready() const
{
    return (!m_campaign.isNull() && !m_characterClasses.isNull());
}
